require 'json'

module JSON_RPC
  def json_request_handler(sym)
    @json_request_handlers ||= {}
    @json_request_handlers[sym.to_s] = sym
    puts "Added json handler: #{sym}"
    puts @json_request_handlers
  end

  def json_notification_handler(sym)
    @json_notification_handlers ||= {}
    @json_notification_handlers[sym.to_s] = sym
  end

  def json_handle_msg(str)
    msg = JSON.parse(str)

    # Request
    if(msg['method'] and msg['params'] and msg['id'])
      json_handle_request(msg['method'], msg['params'], msg['id'])

      # Response
    elsif(msg['id'])
      json_handle_response(msg['result'], msg['error'], msg['id'])

      # Notification
    elsif(msg['method'] and msg['params'] and not msg['id'])
      json_handle_notification(msg['method'], msg['params'])
    end
  end

  def json_request(method, params, &callback)
    puts "request"
    id = json_next_id
    @json_callbacks ||= {}
    @json_callbacks[id] = callback

    {'method' => method, 
      'params' => params, 
      'id' => id}.to_json
  end

  def json_response(result, error, id)
    puts "response"
    {'result' => result, 
      'error' => error, 
      'id' => id}.to_json
  end

  # Notification is just a request with a nil id.
  def json_notification(method, params)
    puts "notification"
    json_request(method, params, nil)
  end

  private

  def json_handle_request(method, params, id)
    puts "handler: #{@json_request_handlers[method]}"
    if @json_request_handlers.has_key?(method)
      send(@json_request_handlers[method], params, id)
    end
  end

  def json_handle_response(result, error, id)
    if @json_callbacks.has_key?(id)
      @json_callbacks[id].call(result, error)
      @json_callbacks.delete(id)
    end
  end

  def json_handle_notification(method, params)
    if @json_notification_handlers.has_key?(method)
      send(@json_notification_handlers[method], params)
    end
  end

  def json_next_id
    @json_id ||= 0
    @json_id += 1
  end
end
